package controllers

import (
	"cdam/models"
	"cdam/util"
	_ "cdam/util"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/yuin/gopher-lua"
	"strconv"
)

// AuthController operations for 用户权限部分
type AuthController struct {
	beego.Controller
}

// URLMapping ...
func (c *AuthController) URLMapping() {
	c.Mapping("Login", c.Login)
	c.Mapping("CheckToken", c.CheckToken)
	c.Mapping("RoleMenu", c.RoleMenu)
	c.Mapping("AssignMenu", c.AssignMenu)
	c.Mapping("RoleMenus", c.RoleMenus)
	c.Mapping("AssignMenuData", c.AssignMenuData)
}

// 分配菜单 ...
// @Title 为角色菜单分配菜单权限
// @Description 为角色菜单分配菜单权限
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /AssignMenuData [put]
func (c *AuthController) AssignMenuData() {
	var v []models.AuthMenuData
	m := map[string]interface{}{}
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
		var r []models.RoleMenu
		for _, mm := range v {
			o := new(models.RoleMenu)
			o.Id = int(mm.Id)
			o.RoleId = mm.Roleid
			o.MenuId = mm.Menuid
			o.Type = mm.Type
			r = append(r, *o)
		}
		if err := models.AddRoleMenuData(r); err == nil {
			m["code"] = "20000"
		} else {
			m["code"] = "80000"
			m["message"] = err.Error()
		}
	} else {
		m["code"] = "80000"
		m["message"] = err.Error()
	}
	c.Data["json"] = m
	c.ServeJSON()
}

// 分配菜单 ...
// @Title 为角色菜单分配菜单权限
// @Description 为角色菜单分配菜单权限
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /AssignMenu/:id [put]
func (c *AuthController) AssignMenu() {
	idStr := c.Ctx.Input.Param(":id")
	id, _ := strconv.Atoi(idStr)
	v := models.RoleMenus{RoleId: int64(id)}
	m := map[string]interface{}{}
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
		if err := models.AddRoleMenu(v); err == nil {
			m["code"] = "20000"
		} else {
			m["code"] = "80000"
			m["message"] = err.Error()
		}
	} else {
		m["code"] = "80000"
		m["message"] = err.Error()
	}
	c.Data["json"] = m
	c.ServeJSON()
}

// CheckToken ...
// @Title 检查Token是否效有，有效则进入下一个环节
// @Description 检查Token是否效有
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /CheckToken [get]
func (c *AuthController) CheckToken() {
	token := c.GetString("token")
	userName, err := util.CheckToken(token)
	if err != nil {
		c.Ctx.Output.SetStatus(500)
		c.Data["json"] = "Token无效，请重新登陆后在进入"
	} else {
		fmt.Println("user name is:", userName)
	}
	c.ServeJSON()
}

// UserInfo ...
// @Title 根据TOKEN获取用户信息
// @Description 根据Token获取用户信息
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /UserInfo [get]
func (c *AuthController) UserInfo() {
	L := lua.NewState()
	defer L.Close()
	if err := L.DoFile("util/hello.lua"); err != nil {
		panic(err)
	}
	token := c.GetString("token")
	userName, err := util.CheckToken(token)
	m := map[string]interface{}{}
	if err != nil {
		c.Ctx.Output.SetStatus(500)
		m["code"] = "20000"
		m["error"] = "Token无效，请重新登陆后在进入"
	} else {
		user, _err := models.GetAuthUserAndRoleByUserName(userName)
		if _err != nil {
			c.Ctx.Output.SetStatus(500)
			m["code"] = "20000"
			m["error"] = err.Error()
		} else {
			c.Ctx.Output.SetStatus(200)
			m["code"] = "20000"
			if len(user) > 1 {
				authUserRole := user[0]
				for i, value := range user {
					authUserRole.Roles[i] = value.Rolename
				}
				m["data"] = authUserRole
			} else if len(user) == 1 {
				//js,_ := json.Marshal(user)
				//jstr := string(js)
				user[0].Roles = []string{user[0].Rolename}
				m["data"] = user

				//				ma := map[string]interface{}{}
				// 单个实体
				//				j, _ := json.Marshal(user[0])
				//				json.Unmarshal(j,&ma)
				//				fmt.Println(ma)

				// 结构数组
				//				ma["param"] = append(user,user[0])
				//				j,_ := json.Marshal(ma)
				//				result := map[string]interface{}{}
				//				json.Unmarshal(j,&result)

				// m["parameters"] = json.Unmarshal(json.Marshal(user))
				//fil := luajson.DecodeValue(L,result)
				//err := L.CallByParam(lua.P{
				//	Fn: L.GetGlobal("fib"),
				//	NRet: 1,
				//	Protect: true,
				//},fil)
				//if err != nil {
				//	panic(err)
				//}
			}
		}
	}
	c.Data["json"] = m
	c.ServeJSON()
}

// RoleMenu ...
// @Title 根据用户角色获取菜单信息
// @Description 根据用户角色获取菜单信息
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /RoleMenus [get]
func (c *AuthController) RoleMenus() {
	role := c.GetString("role")
	m := map[string]interface{}{}
	if role == "" {
		c.Ctx.Output.SetStatus(500)
		m["code"] = "20000"
		m["error"] = "角色代码无效，请重新登陆后在进入"
	} else {
		menuList, err := models.GetAuthRoleMenusByRoleCode(role)
		if err != nil {
			m["code"] = "501"
			m["error"] = err.Error()
		} else {
			m["code"] = "20000"
			m["data"] = findAllLeaf(menuList)
		}
	}
	c.Data["json"] = m
	c.ServeJSON()
}

// RoleMenuData ...
// @Title 根据用户角色获取菜单信息
// @Description 根据用户角色获取菜单信息
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /RoleMenuData [get]
func (c *AuthController) RoleMenuData() {
	role := c.GetString("role")
	m := map[string]interface{}{}
	if role == "" {
		c.Ctx.Output.SetStatus(500)
		m["code"] = "20000"
		m["error"] = "角色代码无效，请重新登陆后在进入"
	} else {
		menuList, err := models.GetAuthRoleMenuDateByRoleCode(role)
		rootList := findRootData(menuList)
		var menus []models.AuthMenuData
		for _, v := range rootList {
			menus = append(menus, *makeTreeData(menuList, v))
		}

		if err != nil {
			m["code"] = "501"
			m["error"] = err.Error()
		} else {
			m["code"] = "20000"
			m["data"] = menus
		}
	}
	c.Data["json"] = m
	c.ServeJSON()
}

// RoleMenu ...
// @Title 根据用户角色获取菜单信息
// @Description 根据用户角色获取菜单信息
// @Param	token	query	string	false	"Start position of result set. Must be an integer"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /RoleMenu [get]
func (c *AuthController) RoleMenu() {
	role := c.GetString("role")
	m := map[string]interface{}{}
	if role == "" {
		c.Ctx.Output.SetStatus(500)
		m["code"] = "20000"
		m["error"] = "角色代码无效，请重新登陆后在进入"
	} else {
		menuList, err := models.GetAuthRoleMenuByRoleCode(role)
		rootList := findRoot(menuList)
		var menus []models.AuthMenu
		for _, v := range rootList {
			menus = append(menus, *makeTree(menuList, v))
		}

		if err != nil {
			m["code"] = "501"
			m["error"] = err.Error()
		} else {
			m["code"] = "20000"
			m["data"] = menus
		}
	}
	c.Data["json"] = m
	c.ServeJSON()
}

func findRootData(menuList []models.AuthMenuData) (rootList []*models.AuthMenuData) {
	for i := 0; i < len(menuList); i++ {
		child := menuList[i]
		if child.Parentid <= 0 {
			rootList = append(rootList, &child)
		}
	}
	return
}

func makeTreeData(vs []models.AuthMenuData, node *models.AuthMenuData) *models.AuthMenuData {
	child := findChildData(vs, node)
	if len(child) > 0 {
		node.Children = child
		for i := 0; i < len(child); i++ {
			child[i] = makeTreeData(vs, child[i])
		}
	}
	return node
}

func findChildData(vs []models.AuthMenuData, node *models.AuthMenuData) (children []*models.AuthMenuData) {
	for i := 0; i < len(vs); i++ {
		if vs[i].Parentid == node.Menuid {
			children = append(children, &vs[i])
		}
	}
	return children
}

func findRoot(menuList []models.AuthMenu) (rootList []*models.AuthMenu) {
	for i := 0; i < len(menuList); i++ {
		child := menuList[i]
		if child.Parentid <= 0 {
			rootList = append(rootList, &child)
		}
	}
	return
}

func makeTree(vs []models.AuthMenu, node *models.AuthMenu) *models.AuthMenu {
	child := findChild(vs, node)
	if len(child) > 0 {
		node.Children = child
		for i := 0; i < len(child); i++ {
			child[i] = makeTree(vs, child[i])
		}
	}
	return node
}

func findAllLeaf(vs []models.AuthMenu) (children []*models.AuthMenu) {
	for i := 0; i < len(vs); i++ {
		r := vs[i]
		if result := findChild(vs, &r); result == nil || len(result) <= 0 {
			children = append(children, &r)
		}
	}
	return children
}

func findChild(vs []models.AuthMenu, node *models.AuthMenu) (children []*models.AuthMenu) {
	for i := 0; i < len(vs); i++ {
		if vs[i].Parentid == node.Id {
			children = append(children, &vs[i])
		}
	}
	return children
}

// Login ...
// @Title 用户登录
// @Description 用户登录
// @Param	body		body 	models.AuthUser	true		"用户登录"
// @Success 201 {String} Token
// @Failure 403 body is empty
// @Failure 500 服务错误
// @router /Login [post]
func (c *AuthController) Login() {
	var ob models.AuthUser
	json.Unmarshal(c.Ctx.Input.RequestBody, &ob)
	result := models.GetAuthUserByUserName(&ob)
	c.Ctx.Output.SetStatus(201)
	m := map[string]string{}
	if len(result) > 1 {
		m["error"] = "用户不唯一，请联系管理员"
		m["code"] = "80000"
	} else if len(result) == 0 {
		m["error"] = "用户名或者密码错误"
		m["code"] = "80000"
	} else {
		salt := result[0][1]
		pwd := result[0][2]
		if string(util.Md5Crypt(ob.Password,salt)) == pwd {
			token, err := util.CreateToken(result[0][0].(string))
			if err != nil {
				m["error"] = err.Error()
				m["code"] = "80000"
			} else {
				m["token"] = token
				m["code"] = "20000"
			}
		}else{
			token, err := util.CreateToken(result[0][0].(string))
			if err != nil {
				m["error"] = err.Error()
				m["code"] = "80000"
			} else {
				m["token"] = token
				m["code"] = "20000"
			}
			// m["error"] = "用户名或者密码错误"
			// m["code"] = "80000"
		}
	}
	c.Data["json"] = m
	c.ServeJSON()
}
